package server;

import java.io.*;
import java.net.*;

/**
 * 
 * @author Roman Shuplov<AstRonin@gmail.com>
 */
public class Server {

    
    static int serverListeningPort1 = 7777;
    static int serverListeningPort2 = 7777;
    static String protocolType1 = "";
    static String protocolType2 = "";


    final static String TCP = "tcp";
    final static String UDP = "udp";

    final static String NEED_PROT = "Need set type protocol: tcp or udp";



    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        switch(args.length){
            case 1:tellArgs1(args); break;
            case 2:tellArgs2(args); break;
            case 3:tellArgs3(args); break;
            case 4:tellArgs4(args); break;
        }

        Server server = new Server();

        server.startServerListeningThread();
        server.startInputThread();

    }

    private static void tellArgs1(String[] args ){
        protocolType1 = tellFor(args[0]);
    }
    private static void tellArgs2(String[] args){
        tellArgs1(args);
        
        try{

            serverListeningPort1 = Integer.parseInt(args[1]);

        }catch(NumberFormatException e){
            protocolType2 = tellFor(args[1]);
        }catch(ArrayIndexOutOfBoundsException e){

            
        }
    }
    private static void tellArgs3(String[] args){
        tellArgs2(args);
        try{

            serverListeningPort2 = Integer.parseInt(args[2]);

        }catch(ArrayIndexOutOfBoundsException e){
        }catch(NumberFormatException e){

            protocolType2 = tellFor(args[2]);

        }
    }
    private static void tellArgs4(String[] args){
        tellArgs3(args);
        try{

            serverListeningPort2 = Integer.parseInt(args[3]);

        }catch(ArrayIndexOutOfBoundsException e){}
    }
    private static String tellFor(String args){
        try{

            if (args.equals(TCP) || args.equals(UDP)) {
                String prt = args.trim();
                return prt;
            }else{
                System.out.println(NEED_PROT);
                System.exit(0);
                return "";
            }

        }catch(ArrayIndexOutOfBoundsException e){
            System.out.println(NEED_PROT);
            System.exit(0);
            return "";
        }
    }


    
    private void startServerListeningThread(){
        if ( 0 < protocolType1.length() ){
            choiceProt(protocolType1);
        }
        if ( 0 < protocolType2.length() ){
            choiceProt(protocolType2);
        }
    }
    private void choiceProt(String protocolType){
        if (protocolType.equals(UDP)) {

            Thread listen = new Thread(new ServerListeningUDPThread());
            listen.start();

        }else if (protocolType.equals(TCP)) {

            Thread listen = new Thread(new ServerListeningTCPThread());
            listen.start();

        }else{
            System.err.println("What protocol?");
        }
    }




    private void startInputThread(){
        Thread input = new Thread(new InputThread());
        input.start();
    }
    private class InputThread implements Runnable{
        @Override
        public void run(){
            synchronized ( Thread.currentThread() ) {
                try{
                    Thread.currentThread().sleep(100);
                }catch(InterruptedException e){
                    System.err.println(e.getMessage());
                    System.exit(0);
                }
            }

            System.out.println("Start thread Input!");
            try {
                for(;;){
                    System.out.print(">");
                    byte[] bufferIn = new byte [100];
                    System.in.read(bufferIn);
                    String s = new String(bufferIn);
                    s = s.trim();

                    if (s.equals("quit") || s.equals("exit")) {
                        System.out.println("Bye!");
                        System.exit(0);
                    }else if (!s.equals("")) {
                        System.out.println(s);
                    }
                }
            } catch (IOException e) {
                // Ничего не делаем, т.к. больше некуда писать сообщения об ошибках
                // System.exit(0); // можем закрыть программу
            }
        }

    }



    
    private class ServerListeningUDPThread implements Runnable{
        @Override
        public void run(){
//            System.out.println("Starting server udp listening!");
            try{
                new ServerListeningUDP();
                notifyAll();
            }catch(SocketException e){
                System.out.println("Error Socket: " + e.getMessage());
                System.exit(0);
            }
        }
    }
    private class ServerListeningUDP{
        public ServerListeningUDP() throws SocketException{
            int serverListeningPort = serverListeningPort1;
            DatagramPacket receivePacket;
            DatagramSocket socket;
            int receivePacketSize = 1024;
            byte[] buffer = new byte[receivePacketSize];
            int clientPort;
            InetAddress clientAddress;

            if ( protocolType1.equals(UDP) ) {
                serverListeningPort = serverListeningPort1;
            }else if (protocolType2.equals(UDP)) {
                serverListeningPort = serverListeningPort2;
            }

            socket = new DatagramSocket(serverListeningPort);

            System.out.println("Start server udp listening!");
            System.out.println("Starting om Port: " + serverListeningPort);

            for(;;){ // Открываем бесконечный цикл для ожидания подключения.
                System.out.println("Waiting...");

                buffer = new byte[receivePacketSize]; // Гинерим новый буффер
                receivePacket = new DatagramPacket(buffer, receivePacketSize); // Создаем новый пакет для данных

                try{

                    
                    socket.receive(receivePacket); // Ожидаем соединение


                }catch(IOException e){
                    System.out.println("Error IN: " + e.getMessage());
                    socket.close(); // Если ошибка, закрываем соединение
                    System.exit(0); // Выходим из программы
                }


                clientAddress = receivePacket.getAddress(); // Адрес клиента
                clientPort = receivePacket.getPort(); // Порт клиента

                // Выводим на консоль, что получили
                String str = new String(buffer, 0, receivePacket.getLength());
                System.out.println("Message :" + str.trim());
                System.out.println("Address :" + clientAddress);
                System.out.println("Port :" + clientPort);


                receivePacket = new DatagramPacket(buffer, receivePacketSize, clientAddress, clientPort);

                try{

                    socket.send(receivePacket); // Возвращаем клиенту, че он послал
    //                socket.close();
                }
                catch(IOException e){
                    System.out.println("Error OUT: " + e.getMessage());
                    socket.close(); // Если ошибка, закрываем соединение
                    System.exit(0); // Выходим из программы
                }
            }
        }
    }


    private class ServerListeningTCPThread implements Runnable{
        @Override
        public void run(){
//            System.out.println("Starting server tcp listening!");
            try{
                new ServerListeningTCP();
                notifyAll();
            }catch(Exception e){
                System.out.println("Error Socket: " + e.getMessage());
                System.exit(0);
            }
        }
    }
    private class ServerListeningTCP{
        public ServerListeningTCP() throws Exception{
            int serverListeningPort = serverListeningPort1;
            ServerSocket serverSocket;
            Socket sock;

            if ( protocolType1.equals(TCP) ) {
                serverListeningPort = serverListeningPort1;
            }else if (protocolType2.equals(TCP)) {
                serverListeningPort = serverListeningPort2;
            }
            
            serverSocket = new ServerSocket(serverListeningPort);

            System.out.println("Start server tcp listening!");
            System.out.println("Starting om Port: " + serverListeningPort);
            
            for(;;){

                System.out.println("Waiting...");


                sock = serverSocket.accept();


                System.out.println("Socket accepted: " + sock);


                try{

                    BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

                    String message = in.readLine();

                    System.out.println("Message :" + message);
                    System.out.println("Address :" + sock.getInetAddress());
                    System.out.println("Port :" + sock.getPort());


                    PrintStream out = new PrintStream(sock.getOutputStream());

                    out.println(message);
                    in.close();
                    out.close();


//                    sock.close();

                }catch(IOException e){
                    System.out.println("Error io: " + e.getMessage());
                    sock.close();
                    System.exit(0);
                }
            }





        }
    }


}





















